package run.halo.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import run.halo.app.cache.AbstractStringCacheStore;
import run.halo.app.exception.ForbiddenException;
import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.User;
import run.halo.app.model.support.PostConstant;
import run.halo.app.security.authentication.Authentication;
import run.halo.app.security.context.SecurityContextHolder;
import run.halo.app.service.PostAuthService;

/**
 * 文章鉴权，普通用户只能操作自己的文章，已经添加普通用户过滤自己的文章，添加校验，双重保险
 */
@Slf4j
@Service
public class PostAuthServiceImpl implements PostAuthService {

    @Autowired
    private AbstractStringCacheStore cacheStore;

    @Override
    public void addCache(Page<Post> postPage) {
        Assert.notNull(postPage, "postPage info must not be null");
        List<Post> posts = postPage.getContent();
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            User user = authentication.getDetail().getUser();
            Map<Integer, Integer> postAndUserMap = new HashMap<>();
            posts.forEach(post -> postAndUserMap.put(post.getId(), post.getUser().getId()));
            cacheStore.put(PostConstant.POST_CACHE_KEY_PRE + user.getId(),
                JSON.toJSONString(postAndUserMap), 30,
                TimeUnit.MINUTES);
        }
    }

    @Override
    public void verifyPost(Integer postId) {
        Assert.notNull(postId, "postId info must not be null");
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            User user = authentication.getDetail().getUser();
            Integer userId = user.getId();
            JSONObject parse = getPostCache(userId);
            if (parse != null) {
                Integer userCacheId = parse.getInteger(String.valueOf(postId));
                // 管理员不用鉴权，=>不是管理员，同时文章不是自己的
                if (user.getUserRole() != 1 && !userCacheId.equals(userId)) {
                    throw new ForbiddenException("不是你的文章");
                }
            }
        }
    }

    @Override
    public void verifyPosts(List<Integer> posts) {
        Assert.notNull(posts, "posts info must not be null");
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            User user = authentication.getDetail().getUser();
            Integer userId = user.getId();
            JSONObject parse = getPostCache(userId);
            if (parse != null) {
                boolean isYouPost = posts.stream().allMatch(postId -> {
                    Integer userCacheId = parse.getInteger(String.valueOf(postId));
                    // 管理员不用鉴权，=>不是管理员，同时文章不是自己的
                    return user.getUserRole() == 1 || userCacheId.equals(userId);
                });
                if (!isYouPost) {
                    throw new ForbiddenException("请选择你自己文章操作");
                }
            }
        }
    }

    @Nullable
    private JSONObject getPostCache(Integer userId) {
        Optional<String> s = cacheStore.get(PostConstant.POST_CACHE_KEY_PRE + userId);
        String str = s.isEmpty() ? "" : s.get();
        return (JSONObject) JSON.parse(str);
    }
}
